/////////////////////////////////////////////////////////////////////////////
// Filename: Transformations.cpp
// Description: 3D transformations using homogeneous coordinates
/////////////////////////////////////////////////////////////////////////////

#include "Transformations.h"

// YOU WRITE CODE HERE FOR ASSIGNMENT 2


//This one you get for free :)
Matrix4 translate(const Vector3 &T)
{
	return Matrix4(
	Vector3h(1,0,0,T[0]),
	Vector3h(0,1,0,T[1]),
	Vector3h(0,0,1,T[2]),
	Vector3h(0,0,0,1));
}

Matrix4 scale(const Vector3 &S)
{
   //return Matrix4().identity();
	return Matrix4(
	Vector3h(S[0],0,0,0),
	Vector3h(0,S[1],0,0),
	Vector3h(0,0,S[2],0),
	Vector3h(0,0,0,1));
}

Matrix4 rotate_x(float theta)
{
   //return Matrix4().identity();
	float cosTheta, sinTheta;

	cosTheta = (float)cos(theta * PI / 180);
	sinTheta = (float)sin(theta * PI / 180);

	return Matrix4(
	Vector3h(1,0,0,0),
	Vector3h(0,cosTheta,-sinTheta,0),
	Vector3h(0,sinTheta,cosTheta,0),
	Vector3h(0,0,0,1));
}

Matrix4 rotate_y(float theta)
{
   //return Matrix4().identity();
	float cosTheta, sinTheta;

	cosTheta = (float)cos(theta * PI / 180);
	sinTheta = (float)sin(theta * PI / 180);

	return Matrix4(
	Vector3h(cosTheta,0,sinTheta,0),
	Vector3h(0,1,0,0),
	Vector3h(-sinTheta,0,cosTheta,0),
	Vector3h(0,0,0,1));

}

Matrix4 rotate_z(float theta)
{
  //return Matrix4().identity();
	float cosTheta, sinTheta;

	cosTheta = (float)cos(theta * PI / 180);
	sinTheta = (float)sin(theta * PI / 180);

	return Matrix4(
	Vector3h(cosTheta,-sinTheta,0,0),
	Vector3h(sinTheta,cosTheta,0,0),
	Vector3h(0,0,1,0),
	Vector3h(0,0,0,1));
}

Matrix4 rotate(const Vector3 &axis, float theta, const Vector3 &point)
{
	Matrix4 translateMatrix = translate(point);
	Matrix4 invTranslateMatrix = translateMatrix.inv();

	Vector3 v1 = axis;
	Vector3 vPrime, v2, v3;

	Vector3 u1(1,0,0);
	Vector3 u2(0,1,0);

	Vector3 temp1 = v1 ^ u1;
	Vector3 temp2 = v1 ^ u2;

	if(temp1.abs() > temp2.abs()) {
		vPrime = u1; 
	}
	else {
		vPrime = u2;
	}

	v2 = v1 ^ vPrime;
	v2 = v2.normalize();

	v3 = v1 ^ v2;
	v3 = v3.normalize();

	Matrix4 changeCoordMatrix  = Matrix4(v1,
										v2,
										v3,
										Vector3h(0,0,0,1));


	Matrix4 rotateMatrix = rotate_x(theta);

	Matrix4 invChangeCoordMatrix = changeCoordMatrix.inv();

	return invTranslateMatrix * invChangeCoordMatrix * rotateMatrix * changeCoordMatrix * translateMatrix;
}


Matrix4 look_at(const Vector3 &eye, const Vector3 &at, const Vector3 &up)
{
	//return Matrix4().identity();

	Vector3 upNorm = up;
	upNorm = upNorm.normalize();

	Vector3 fz = eye - at;
	fz = fz.normalize();
	
	Vector3 fx = upNorm ^ fz;
	fx = fx.normalize();

	Vector3 fy = fz ^ fx;

	//must use negative fz values since we're using a right-handed coordinate
	//system, which reverses the z-direction
	Matrix4 rotation = Matrix4(
		Vector3h(fx.x, fy.x, -1*fz.x, 0),
		Vector3h(fx.y, fy.y, -1*fz.y, 0),
		Vector3h(fx.z, fy.z, -1*fz.z, 0),
		Vector3h(0,0,0,1));

	Matrix4 translation = Matrix4(
		Vector3h(1,0,0,eye.x),
		Vector3h(0,1,0,eye.y),
		Vector3h(0,0,1,eye.z),
		Vector3h(0,0,0,1));

	Matrix4 view = rotation * translation;
	return view;
}


/////////////////////////////////////////////////////////////////////////////
//                               END OF FILE                               //
/////////////////////////////////////////////////////////////////////////////

